import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
from sklearn.datasets import make_blobs
import time
import platform

# Set font based on operating system
if platform.system() == 'Windows':
    plt.rcParams['font.sans-serif'] = ['SimHei']  # Windows common Chinese font
elif platform.system() == 'Darwin':  # macOS
    plt.rcParams['font.sans-serif'] = ['STHeiti']
else:  # Linux or other
    plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']  # Example font, may vary based on system

# Set minus sign to display correctly
plt.rcParams['axes.unicode_minus'] = False

# Generate synthetic data for two separable classes
def generate_data(n_samples=30):
    X, y = make_blobs(n_samples=n_samples, centers=2, random_state=42, cluster_std=1.2)
    return X, y

# Plot SVM decision boundary and margin dynamically
def animate_svm(X, y):
    plt.ion()  # Turn on interactive mode
    fig, ax = plt.subplots(figsize=(8, 6))
    
    # Initialize an SVM model with a linear kernel
    clf = svm.SVC(kernel='linear', C=1.0)

    # Fit the model incrementally and update the plot
    for i in range(2, len(X) + 1):  # Start with two points and add incrementally
        clf.fit(X[:i], y[:i])  # Fit only up to the ith point

        # Get the separating hyperplane
        w = clf.coef_[0]
        b = clf.intercept_[0]
        x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
        y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
        xx = np.linspace(x_min, x_max, 50)
        yy = (-w[0] * xx - b) / w[1]

        # Plot current data points and decision boundary
        ax.cla()  # Clear previous plots
        ax.scatter(X[y == 0][:i, 0], X[y == 0][:i, 1], color='blue', label='类别 0', edgecolor='k')
        ax.scatter(X[y == 1][:i, 0], X[y == 1][:i, 1], color='red', label='类别 1', edgecolor='k')
        ax.plot(xx, yy, 'k-', label='决策边界')

        # Plot margin boundaries
        margin = 1 / np.linalg.norm(w)
        yy_up = yy + margin
        yy_down = yy - margin
        ax.plot(xx, yy_up, 'k--', label='边界 (正间隔)')
        ax.plot(xx, yy_down, 'k--', label='边界 (负间隔)')

        # Highlight support vectors
        ax.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], s=100, facecolors='none', edgecolor='k', label='支持向量')

        # Set plot limits and labels
        ax.set_xlim(x_min, x_max)
        ax.set_ylim(y_min, y_max)
        ax.set_xlabel("特征 1")
        ax.set_ylabel("特征 2")
        ax.legend(loc='upper right')
        ax.set_title("SVM 决策边界动画")
        
        plt.draw()
        plt.pause(0.5)  # Pause for animation effect

    plt.ioff()  # Turn off interactive mode
    plt.show()

if __name__ == "__main__":
    # Generate data and animate SVM
    X, y = generate_data()
    animate_svm(X, y)